Skip to content

Conversation

crazyair
Copy link
Contributor

@crazyair crazyair commented Sep 11, 2025

Summary by CodeRabbit

  • 新功能

  • Bug 修复

    • 修复 useWatch 在依赖为函数时初始值未根据依赖计算的问题,提升首屏渲染一致性与数据准确性。
  • 文档

    • 更新示例,新增本地监听展示与值的可视化输出,便于调试与理解使用场景。

Copy link

vercel bot commented Sep 11, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
field-form Ready Ready Preview Comment Sep 22, 2025 0:13am

Copy link

coderabbitai bot commented Sep 11, 2025

Walkthrough

本次变更在示例与核心逻辑两处更新:示例增加一个基于依赖函数的本地 useWatch 用法与调试输出;核心 hook(useWatch)在初始化时支持当 dependencies 为函数时用 dependencies({}) 结果作为初始值,其它行为保持不变。

Changes

Cohort / File(s) 摘要
示例:useWatch 使用
docs/examples/useWatch-selector.tsx
增加 ESLint no-shadow 禁用注释;新增本地 watch:base = Form.useWatch(values => ({ newName: values.name }), form)console.log;在表单中渲染 values 的 JSON 字符串;格式化微调。
核心 Hook:useWatch 初始化
src/useWatch.ts
useState 初始值:当 dependencies 为函数时使用 dependencies({}),否则为 undefinedtriggerUpdate 内部三元表达式去除冗余括号,逻辑不变。

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant F as Form
  participant UW as useWatch
  participant D as dependencies(fn)
  participant S as State

  U->>F: 打开示例页面
  F->>UW: 初始化 useWatch(dependencies)
  alt dependencies 是函数
    UW->>D: 调用 dependencies({})
    D-->>UW: 返回初始派生值
    UW->>S: setState(派生值)
  else 非函数/未提供
    UW->>S: setState(undefined)
  end

  note over F,UW: 表单交互触发值变化
  F->>UW: triggerUpdate(allValues/values, preserve)
  UW->>UW: 选择 allValues ?? getFieldsValue(true) 或 values ?? getFieldsValue()
  UW->>S: setState(新值)
  UW-->>F: 返回最新 watch 值
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Pre-merge checks (2 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed 标题 “useWatch selector init” 简短且聚焦,直接反映了变更集中对 useWatch 初始化逻辑(在 src/useWatch.ts 中通过 dependencies 初始化初始值)和示例中 selector 相关改动的主要意图,因此能够让审阅者快速识别主要改动。该标题没有包含噪音或无关信息,故符合检查要求。

Poem

小兔敲键轻点头,
初值如今函里求;
表单起伏风吹麦,
依赖一动值自流。
咔嗒日志亮屏幽,
watch 眨眼同步收。

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @crazyair, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request improves the useWatch hook by ensuring that its selector function is invoked during the initial render, providing a more robust and predictable initial value for watched form fields. This change enhances the hook's reliability and is accompanied by an updated documentation example.

Highlights

  • useWatch Initialization: The useWatch hook now initializes its internal state by executing the provided selector function (if it's a function) on the initial render. This ensures that the watched value is immediately available and consistent with the form's initial state.
  • Documentation Example: A new example has been added to docs/examples/useWatch-selector.tsx to demonstrate the updated initialization behavior and usage of the useWatch hook with a selector.
  • Code Refinement: A minor refactoring was applied to the triggerUpdate function in src/useWatch.ts to simplify a conditional expression, improving code readability.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

codecov bot commented Sep 11, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.53%. Comparing base (2b0f66b) to head (1a98550).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #762   +/-   ##
=======================================
  Coverage   99.53%   99.53%           
=======================================
  Files          19       19           
  Lines        1287     1288    +1     
  Branches      319      316    -3     
=======================================
+ Hits         1281     1282    +1     
  Misses          6        6           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an improvement to the useWatch hook by initializing its state when a selector function is used. This ensures that the hook returns a more predictable value on the initial render, derived from an empty store, rather than undefined. The change in src/useWatch.ts is well-implemented. The new example in docs/examples/useWatch-selector.tsx is helpful for demonstrating this, but it includes a console.log statement which should be removed for code cleanliness.

export default () => {
const [form] = Form.useForm<FieldType>();
const base = Form.useWatch(values => ({ newName: values.name }), form);
console.log('base', base);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's best to remove console.log statements from the code, even in examples, to keep it clean and avoid potential noise in browser consoles for users of the documentation.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
docs/examples/useWatch-selector.tsx (4)

1-1: 不建议全局关闭 no-shadow,直接避免同名遮蔽即可

移除全局 eslint-disable,通过重命名变量解决遮蔽问题更安全。见下方重命名建议。

-/* eslint-disable @typescript-eslint/no-shadow */

14-16: 示例中的 console.log 建议只在开发环境打印或移除

避免示例页面在生产文档中产生噪声输出。

-  console.log('base', base);
+  if (process.env.NODE_ENV !== 'production') {
+    // 示例调试输出
+    console.log('base', base);
+  }

17-22: 通过重命名外层变量避免与 selector 参数同名,移除 no-shadow 关闭

重命名外层 values,即可删除顶部的 eslint-disable

-  const values = Form.useWatch(
+  const watchedValues = Form.useWatch(
     values => ({ init: values.init, newName: values.name, newAge: values.age }),
     { form, preserve: true },
   );
-  console.log('values', values);
+  console.log('values', watchedValues);

38-39: 配合重命名,同步更新渲染展示;并可提升可读性

可用 JSON.stringify 的缩进参数增强可读性。

-        values:{JSON.stringify(values)}
+        values:
+        {JSON.stringify(watchedValues, null, 2)}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b0f66b and 250a65a.

📒 Files selected for processing (2)
  • docs/examples/useWatch-selector.tsx (2 hunks)
  • src/useWatch.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
docs/examples/useWatch-selector.tsx (1)
.eslintrc.js (1)
  • base (1-1)
🔇 Additional comments (1)
src/useWatch.ts (1)

120-124: 分支选择逻辑语义正确

仅格式化调整,preserve 分支与非 preserve 分支的兜底获取逻辑保持不变,无功能性回归。

src/useWatch.ts Outdated
Comment on lines 95 to 97
const [value, setValue] = useState<any>(
typeof dependencies === 'function' ? dependencies({}) : undefined,
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

避免在渲染期间每次都执行 selector,且防止初始空对象导致崩溃

  • 这里直接执行 dependencies({}) 属于非惰性初始化:每次渲染都会调用 selector,有性能隐患。
  • 若 selector 存在深链访问(如 values.user.profile.name),传入 {} 可能在初次渲染直接抛错,造成不可恢复的渲染失败。

建议改为惰性初始化并用 try/catch 兜底,仅在首渲染执行一次;失败时回退为 undefined,由后续 triggerUpdate 补齐值。

-  const [value, setValue] = useState<any>(
-    typeof dependencies === 'function' ? dependencies({}) : undefined,
-  );
+  const [value, setValue] = useState<any>(() => {
+    if (typeof dependencies === 'function') {
+      try {
+        return dependencies({} as any);
+      } catch {
+        return undefined;
+      }
+    }
+    return undefined;
+  });

可选优化(如需“首屏即有表单初值”而非 {}):在拿到 formInstance 后用其 getFieldsValue 进行惰性初始化(需要将 useContext(FieldContext) 等取到 formInstance 的逻辑前移到 useState 之前)。

// 仅为思路示例:确保 hooks 顺序稳定
const fieldContext = useContext(FieldContext);
const formInstance = (form as InternalFormInstance) || fieldContext;
const isValidForm = formInstance && formInstance._init;

const [value, setValue] = useState<any>(() => {
  if (typeof dependencies === 'function' && isValidForm) {
    const initial = options.preserve
      ? formInstance.getFieldsValue(true)
      : formInstance.getFieldsValue();
    try {
      return dependencies(initial);
    } catch {
      return undefined;
    }
  }
  return undefined;
});

@crazyair
Copy link
Contributor Author

@gemini-code-assist Review it

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

这个 PR 修复了 useWatch 在使用选择器函数作为依赖时,初始渲染时返回值不正确的问题。通过在 useState 初始化时使用选择器函数处理一个空对象来生成初始值,确保了初始渲染的一致性。相关的示例和测试用例也已更新,以验证此修复。

我的主要反馈是,直接用空对象调用选择器函数可能不够健壮,如果选择器函数期望特定的数据结构,可能会导致运行时崩溃。我建议增加一个 try-catch 来提高代码的容错性。

@zombieJ zombieJ merged commit 4fcb7da into react-component:master Sep 24, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants